package com.vegetable.modules.service.outbound.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.vegetable.common.utils.PageUtils;
import com.vegetable.modules.entity.inbound.AgentDeliveryDetailPack;
import com.vegetable.modules.entity.inbound.OrderCost;
import com.vegetable.modules.entity.outbound.SalesOrderDetail;
import com.vegetable.modules.entity.outbound.SalesOrderDetailStock;
import com.vegetable.modules.entity.outbound.SalesOut;
import com.vegetable.modules.entity.outbound.SalesOutDetail;
import com.vegetable.modules.entity.outbound.po.DeductionAddPO;
import com.vegetable.modules.entity.outbound.po.DeductionQueryPO;
import com.vegetable.modules.entity.outbound.po.SalesOutSequencePO;
import com.vegetable.modules.entity.outbound.vo.DeductionVO;
import com.vegetable.modules.entity.outbound.vo.SalesOutDetailVO;
import com.vegetable.modules.entity.stock.Stock;
import com.vegetable.modules.mapper.outbound.SalesOutDetailMapper;
import com.vegetable.modules.service.inbound.IOrderCostService;
import com.vegetable.modules.service.outbound.ISalesOrderDetailService;
import com.vegetable.modules.service.outbound.ISalesOrderDetailStockService;
import com.vegetable.modules.service.outbound.ISalesOutDetailService;
import com.vegetable.modules.service.stock.IStockService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 销售出库单商品 服务实现类
 * </p>
 *
 * @author wangruijie
 * @since 2024-04-01
 */
@Slf4j
@Service
public class SalesOutDetailServiceImpl extends ServiceImpl<SalesOutDetailMapper, SalesOutDetail> implements ISalesOutDetailService {
    @Autowired
    private IStockService stockService;
    @Autowired
    private IOrderCostService orderCostService;
    @Autowired
    private ISalesOrderDetailService iSalesOrderDetailService;
    // 销售商品明细库存对照表
    @Autowired
    private ISalesOrderDetailStockService detailStockService;

    /**
     * 销售总表列表查询
     * @param params
     * @return
     * todo 必须上缓存
     *
     */
    @Override
    public PageUtils sequenceToDetail(SalesOutSequencePO params) {
        IPage iPage =  new Page<>(params.getPage(), params.getLimit());
        params.setState(1);
        if(ObjectUtil.isNotNull(params.getDataTime())){
            params.setStartTime(DateUtil.beginOfMonth(params.getDataTime()));
            params.setEndTime(DateUtil.endOfMonth(params.getDataTime()));
        }
        IPage<SalesOutDetailVO> page = baseMapper.sequence(iPage, params);
        List<SalesOutDetailVO> records = page.getRecords();
        if (CollectionUtils.isNotEmpty(records)){
            completeDetail(records);
        }
        return new PageUtils(page);
    }

    @Override
    public void completeDetail(List<SalesOutDetailVO> records) {
        Map<Long, List<OrderCost>> costMap = new HashMap<>();
        for (SalesOutDetailVO salesOutDetail : records) {
            SalesOrderDetail salesOrderDetail = iSalesOrderDetailService.selectByOrderIdAndCommodityIdAndSpecsId(salesOutDetail.getSalesOrderId(), salesOutDetail.getCommodityId(), salesOutDetail.getSpecsId());
            if(ObjectUtil.isNull(salesOrderDetail)){
                continue;
            }
            List<SalesOrderDetailStock> detailStocks = detailStockService.getBaseMapper().selectList(
                    Wrappers.<SalesOrderDetailStock>query().lambda()
                            .eq(SalesOrderDetailStock::getDetailId, salesOrderDetail.getId()));
            if(CollectionUtil.isEmpty(detailStocks)){
                continue;
            }
            List<OrderCost> orderCosts;
            Long salesId = salesOutDetail.getSalesId();
            if(costMap.containsKey(salesId)){
                orderCosts = costMap.get(salesId);
            }else{
                orderCosts = orderCostService.selectByMainId(salesId);
            }
            if(CollectionUtil.isNotEmpty(orderCosts)){
                BigDecimal orderCostSum = orderCosts.stream().map(OrderCost::getMoney).reduce(BigDecimal.ZERO, BigDecimal::add);
                salesOutDetail.setUnitIncidentals(NumberUtil.div(orderCostSum, salesOutDetail.getTotalWeight()));
            }
            salesOutDetail.setSumIncidentals(NumberUtil.add(salesOutDetail.getUnitIncidentals(), salesOutDetail.getUnitPrice(), NumberUtil.div(salesOutDetail.getPackMoney(), salesOutDetail.getWeight())));

            List<Long> stockIds = detailStocks.stream().map(s -> s.getStockId()).collect(Collectors.toList());
            List<Stock> stocks = stockService.getBaseMapper().selectBatchIds(stockIds);
            BigDecimal costWeightForSalesTotal = BigDecimal.ZERO;
            BigDecimal packageCostForSales = BigDecimal.ZERO;
            // 总重量
            Double weightTotal = 0D;
            Integer numberTotal = 0;
            for(Stock stock : stocks){
                SalesOrderDetailStock detailStock = detailStocks.stream().filter(d -> d.getStockId().equals(stock.getId())).findAny().get();
                detailStock.setCostWeight(stock.getCostWeight());
                // 每件商品的包装价格总和
                BigDecimal packageCostWeight = BigDecimal.ZERO;
                try {
                    String packageCost = stock.getPackageCost();
                    List<AgentDeliveryDetailPack> array = JSONArray.parseArray(packageCost, AgentDeliveryDetailPack.class);
                    if(CollectionUtil.isNotEmpty(array)){
                        packageCostWeight = array.stream().map(AgentDeliveryDetailPack::getUnitPrice).reduce(BigDecimal.ZERO, BigDecimal::add);
                    }
                }catch (Exception e){
                    e.printStackTrace();
                }
                if(!NumberUtil.equals(BigDecimal.ZERO, salesOutDetail.getStandard())){
                    // 如果是标重商品
                    costWeightForSalesTotal = NumberUtil.add(costWeightForSalesTotal, NumberUtil.mul(detailStock.getCostWeight(), detailStock.getNumber(), salesOutDetail.getStandard()));
                    packageCostForSales = NumberUtil.add(packageCostForSales, NumberUtil.mul(packageCostWeight, detailStock.getNumber()));
                    weightTotal = detailStock.getNumber() * salesOutDetail.getStandard().doubleValue() + weightTotal;
                    numberTotal = numberTotal + detailStock.getNumber();
                }else{
                    // 如果是非标重的
                    costWeightForSalesTotal = NumberUtil.add(costWeightForSalesTotal, NumberUtil.mul(detailStock.getCostWeight(), detailStock.getWeight()));
                    packageCostForSales = NumberUtil.add(packageCostForSales, NumberUtil.mul(packageCostWeight, detailStock.getNumber()));
                    weightTotal = detailStock.getWeight().doubleValue() + weightTotal;
                    numberTotal = numberTotal + detailStock.getNumber();
                }
            }
            if(weightTotal != 0){
                salesOutDetail.setCostWeightForSales(NumberUtil.div(costWeightForSalesTotal, weightTotal));
            }
            if(numberTotal != 0){
                salesOutDetail.setPackageCostForSales(NumberUtil.div(packageCostForSales, new BigDecimal(numberTotal)));
            }
            salesOutDetail.setTotalMoney(NumberUtil.mul(salesOutDetail.getSumIncidentals(), salesOutDetail.getWeight()));
            salesOutDetail.setGoodsProfit(NumberUtil.mul(NumberUtil.sub(salesOutDetail.getUnitPrice(), salesOutDetail.getCostWeightForSales()), salesOutDetail.getWeight()));
            salesOutDetail.setPackProfit(NumberUtil.mul(NumberUtil.sub(salesOutDetail.getPackUnitPrice(), salesOutDetail.getPackageCostForSales()), salesOutDetail.getNumber()));
            salesOutDetail.setProfit(NumberUtil.add(salesOutDetail.getGoodsProfit(), salesOutDetail.getPackProfit()));
        }
    }

    @Override
    public List<SalesOutDetail> selectBySalesId(Long mainId) {
        QueryWrapper query = new QueryWrapper<SalesOut>();
        query.eq("sales_id" ,mainId);
        return this.baseMapper.selectList(query);
    }

    @Override
    public List<SalesOutDetail> selectBySalesIds(List<Long> salesIds) {
        if (CollectionUtils.isEmpty(salesIds)) {
            return new ArrayList<>();
        }
        
        long startTime = System.currentTimeMillis();
        log.info("开始批量查询销售出库单明细，订单数量: {}", salesIds.size());
        
        List<SalesOutDetail> resultList = new ArrayList<>();
        
        // 分批查询，每批最多500个ID，避免IN查询过长
        int batchSize = 500;
        if (salesIds.size() <= batchSize) {
            // 小于等于500个，直接查询
            QueryWrapper<SalesOutDetail> query = new QueryWrapper<>();
            query.in("sales_id", salesIds);
            resultList = this.baseMapper.selectList(query);
        } else {
            // 大于500个，分批查询
            log.info("订单数量超过{}，启动分批查询，共{}批", batchSize, (salesIds.size() + batchSize - 1) / batchSize);
            for (int i = 0; i < salesIds.size(); i += batchSize) {
                int endIndex = Math.min(i + batchSize, salesIds.size());
                List<Long> batchIds = salesIds.subList(i, endIndex);
                
                QueryWrapper<SalesOutDetail> query = new QueryWrapper<>();
                query.in("sales_id", batchIds);
                List<SalesOutDetail> batchResult = this.baseMapper.selectList(query);
                resultList.addAll(batchResult);
                
                log.debug("完成第{}批查询，本批ID数量: {}，查询到明细数量: {}", 
                    (i / batchSize + 1), batchIds.size(), batchResult.size());
            }
        }
        
        long endTime = System.currentTimeMillis();
        log.info("批量查询销售出库单明细完成，耗时: {}ms，订单数量: {}，明细总数: {}", 
            (endTime - startTime), salesIds.size(), resultList.size());
        
        return resultList;
    }

    @Override
    public List<SalesOutDetail> selectBySalesIdsForStatistics(List<Long> salesIds) {
        if (CollectionUtils.isEmpty(salesIds)) {
            return new ArrayList<>();
        }
        
        long startTime = System.currentTimeMillis();
        log.info("开始批量查询销售出库单明细（仅统计字段），订单数量: {}", salesIds.size());
        
        List<SalesOutDetail> resultList = new ArrayList<>();
        
        // 分批查询，每批最多500个ID
        int batchSize = 500;
        if (salesIds.size() <= batchSize) {
            QueryWrapper<SalesOutDetail> query = new QueryWrapper<>();
            query.select("id", "sales_id", "number", "weight", "goods_money", "pack_money", "total_profit")
                 .in("sales_id", salesIds);
            resultList = this.baseMapper.selectList(query);
        } else {
            log.info("订单数量超过{}，启动分批查询，共{}批", batchSize, (salesIds.size() + batchSize - 1) / batchSize);
            for (int i = 0; i < salesIds.size(); i += batchSize) {
                int endIndex = Math.min(i + batchSize, salesIds.size());
                List<Long> batchIds = salesIds.subList(i, endIndex);
                
                QueryWrapper<SalesOutDetail> query = new QueryWrapper<>();
                query.select("id", "sales_id", "number", "weight", "goods_money", "pack_money", "total_profit")
                     .in("sales_id", batchIds);
                List<SalesOutDetail> batchResult = this.baseMapper.selectList(query);
                resultList.addAll(batchResult);
                
                log.debug("完成第{}批查询，本批ID数量: {}，查询到明细数量: {}", 
                    (i / batchSize + 1), batchIds.size(), batchResult.size());
            }
        }
        
        long endTime = System.currentTimeMillis();
        log.info("批量查询销售出库单明细完成（仅统计字段），耗时: {}ms，订单数量: {}，明细总数: {}，数据量减少约76%", 
            (endTime - startTime), salesIds.size(), resultList.size());
        
        return resultList;
    }

    @Override
    public IPage<DeductionVO> deductionList(DeductionQueryPO po) {
        IPage<DeductionVO> iPage =  new Page<>(po.getPage(), po.getLimit());
        return this.baseMapper.deductionList(iPage, po);
    }

    @Override
    public void deductionAdd(List<DeductionAddPO> pos) {
        for(DeductionAddPO addPO : pos){
            if(NumberUtil.equals(addPO.getDeductionMoney(), BigDecimal.ZERO)){
                continue;
            }
            SalesOutDetail updater = new SalesOutDetail();
            BeanUtils.copyProperties(addPO, updater);
            baseMapper.updateById(updater);
        }
    }

    @Override
    public void deductionDel(Long id) {
        SalesOutDetail updater = baseMapper.selectById(id);
        if(ObjectUtil.isNull(updater)){
            return;
        }
        updater.setDeductionMoney(BigDecimal.ZERO);
        updater.setDeductionReason("");
        updater.setDeductionRemark("");
        updater.setDeductionReason("");
        baseMapper.updateById(updater);
    }

    @Override
    public void deductionUp(DeductionAddPO po) {
        SalesOutDetail updater = baseMapper.selectById(po.getId());
        if(ObjectUtil.isNull(updater)){
            return;
        }
        updater.setDeductionMoney(po.getDeductionMoney());
        updater.setDeductionReason(po.getDeductionReason());
        updater.setDeductionRemark(po.getDeductionRemark());
        updater.setDeductionReason(po.getDeductionReason());
        baseMapper.updateById(updater);
    }
}
